package java_option.audio_a031.audio;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

/**
 * 
 * @author java红了 | java_option <br>
 *         2020-11-920:27:17
 */
public class AudioPlay {

	public static void main(String[] args) {

		File file = new File("d:/test/收藏/张靓颖-千百度.wav");
		new AudioPlay().play(file.getPath(), 0);
	}

	/**
	 * 
	 * @param file
	 * @param microseconds 微秒
	 */
	public void play(String filePath, long microseconds) {
		try {
			RandomAccessFile raf = new RandomAccessFile(filePath, "rw");

//
			System.out.println("--------RIFF--------");
			print(raf, 4, false);
			print(raf, 4, true);
			print(raf, 4, false);

//
			System.out.println("--------FORMAT--------");
			print(raf, 4, false);
			print(raf, 4, true);
			print(raf, 2, true);
			int channels = (int) print(raf, 2, true); //

			int sampleRate = (int) print(raf, 4, true); //
			print(raf, 4, true);
			print(raf, 2, true);
			int sampleSizeInBits = (int) print(raf, 2, true); //

//
			System.out.println("--------DATA--------");
			print(raf, 4, false);
			print(raf, 4, true);

			boolean isBigEndian = true;
			AudioFormat format = new AudioFormat(sampleRate, sampleSizeInBits, channels, true, isBigEndian);

			final SourceDataLine auline;
			DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

			try {
				auline = (SourceDataLine) AudioSystem.getLine(info);
				auline.open(format);
			} catch (LineUnavailableException e) {
				e.printStackTrace();
				return;
			} catch (Exception e) {
				e.printStackTrace();
				return;
			}
			auline.start();
			try {
//
				int headSize = 12 + 24 + 8;
//
				final int bytePerSec = sampleRate * channels * sampleSizeInBits / 8;
				long skipData = microseconds * bytePerSec / (1000 * 1000);
				int blockAlign = channels * sampleSizeInBits / 8;
//
				if (skipData % blockAlign != 0) {
//
					skipData -= skipData % skipData;
				}
				raf.seek(headSize + skipData);
//
				int bytePerFrame = sampleSizeInBits * channels / 8;
				byte[] data = new byte[bytePerFrame];
//
				System.out.println("准备播放 " + filePath);
				System.out.println(microseconds);

				while (raf.read(data) > 0) {
					if (isBigEndian) {
						byte[] little4 = revers(data);
//						little4[0] = 0;	//关闭左侧音响
//						little4[1] = 0;
//						little4[2] = 0;	// 关闭右侧音响
//						little4[3] = 0;	
						auline.write(little4, 0, little4.length);
					} else {
						auline.write(data, 0, data.length);
					}
				}
//
				auline.close();
				raf.close();
			} catch (IOException e) {
				e.printStackTrace();
			}

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static byte[] revers(byte[] tmp) {
		byte[] reversed = new byte[tmp.length];
		for (int i = 0; i < tmp.length; i++) {
			reversed[i] = tmp[tmp.length - i - 1];
		}
		return reversed;
	}

	private static Serializable print(RandomAccessFile raf, int byteSize, boolean isLittle) {
		byte[] data = new byte[byteSize];
		try {
			raf.read(data);
			if (isLittle) {
//
				if (byteSize == 4) {
					int value = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).getInt();
					System.out.println(value);
					return value;
				} else {
					int value = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).getShort();
					System.out.println(value);
					return value;
				}
			} else {
				String str = new String(data);
				System.out.println(str);
				return str;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

}
